{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import tensorflow as tf "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 模型构建"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## VGG块的构建"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "def vgg_block(num_conv,num_filters):\n",
    "    # 序列模型\n",
    "    blk = tf.keras.models.Sequential()\n",
    "    # 遍历卷积层\n",
    "    for _ in range(num_conv):\n",
    "        # 设置卷积层\n",
    "        blk.add(tf.keras.layers.Conv2D(num_filters,kernel_size=3,padding='same',activation=\"relu\"))\n",
    "    # 池化层\n",
    "    blk.add(tf.keras.layers.MaxPool2D(pool_size=2,strides=2))\n",
    "    return blk"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 构建模型"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "def vgg(conv_arch):\n",
    "    # 序列模型\n",
    "    net = tf.keras.models.Sequential()\n",
    "    # 生成卷积部分\n",
    "    for (num_convs,num_filters) in conv_arch:\n",
    "        net.add(vgg_block(num_convs,num_filters))\n",
    "    # 全连接层\n",
    "    net.add(tf.keras.models.Sequential([\n",
    "        # 展评\n",
    "        tf.keras.layers.Flatten(),\n",
    "        # 全连接层\n",
    "        tf.keras.layers.Dense(4096,activation=\"relu\"),\n",
    "        # 随机失活\n",
    "        tf.keras.layers.Dropout(0.5),\n",
    "        # 全连接层\n",
    "        tf.keras.layers.Dense(4096,activation=\"relu\"),\n",
    "        # 随机失活\n",
    "        tf.keras.layers.Dropout(0.5),\n",
    "        # 输出层\n",
    "        tf.keras.layers.Dense(10,activation=\"softmax\")\n",
    "    ]))\n",
    "    return net"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 卷积块的参数\n",
    "conv_arch = ((2,64),(2,128),(3,256),(3,512),(3,512))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "net = vgg(conv_arch)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Model: \"sequential\"\n",
      "_________________________________________________________________\n",
      "Layer (type)                 Output Shape              Param #   \n",
      "=================================================================\n",
      "sequential_1 (Sequential)    (1, 112, 112, 64)         37568     \n",
      "_________________________________________________________________\n",
      "sequential_2 (Sequential)    (1, 56, 56, 128)          221440    \n",
      "_________________________________________________________________\n",
      "sequential_3 (Sequential)    (1, 28, 28, 256)          1475328   \n",
      "_________________________________________________________________\n",
      "sequential_4 (Sequential)    (1, 14, 14, 512)          5899776   \n",
      "_________________________________________________________________\n",
      "sequential_5 (Sequential)    (1, 7, 7, 512)            7079424   \n",
      "_________________________________________________________________\n",
      "sequential_6 (Sequential)    (1, 10)                   119586826 \n",
      "=================================================================\n",
      "Total params: 134,300,362\n",
      "Trainable params: 134,300,362\n",
      "Non-trainable params: 0\n",
      "_________________________________________________________________\n"
     ]
    }
   ],
   "source": [
    "X = tf.random.uniform((1,224,224,1))\n",
    "y = net(X)\n",
    "net.summary()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 数据读取"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "from tensorflow.keras.datasets import mnist\n",
    "# 获取手写数字数据集\n",
    "(train_images, train_labels), (test_images, test_labels) = mnist.load_data()\n",
    "# 训练集数据维度的调整：N H W C\n",
    "train_images = np.reshape(train_images,(train_images.shape[0],train_images.shape[1],train_images.shape[2],1))\n",
    "# 测试集数据维度的调整：N H W C\n",
    "test_images = np.reshape(test_images,(test_images.shape[0],test_images.shape[1],test_images.shape[2],1))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 定义两个方法随机抽取部分样本演示\n",
    "# 获取训练集数据\n",
    "def get_train(size):\n",
    "    # 随机生成要抽样的样本的索引\n",
    "    index = np.random.randint(0, np.shape(train_images)[0], size)\n",
    "    # 将这些数据resize成22*227大小\n",
    "    resized_images = tf.image.resize_with_pad(train_images[index],224,224,)\n",
    "    # 返回抽取的\n",
    "    return resized_images.numpy(), train_labels[index]\n",
    "# 获取测试集数据 \n",
    "def get_test(size):\n",
    "    # 随机生成要抽样的样本的索引\n",
    "    index = np.random.randint(0, np.shape(test_images)[0], size)\n",
    "    # 将这些数据resize成224*224大小\n",
    "    resized_images = tf.image.resize_with_pad(test_images[index],224,224,)\n",
    "    # 返回抽样的测试样本\n",
    "    return resized_images.numpy(), test_labels[index]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 获取训练样本和测试样本\n",
    "train_images,train_labels = get_train(256)\n",
    "test_images,test_labels = get_test(128)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 模型编译"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 指定优化器，损失函数和评价指标\n",
    "optimizer = tf.keras.optimizers.SGD(learning_rate=0.01, momentum=0.0)\n",
    "\n",
    "net.compile(optimizer=optimizer,\n",
    "              loss='sparse_categorical_crossentropy',\n",
    "              metrics=['accuracy'])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 模型训练"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 1/3\n",
      "2/2 [==============================] - 65s 32s/step - loss: 2.3255 - accuracy: 0.0783 - val_loss: 2.1876 - val_accuracy: 0.3462\n",
      "Epoch 2/3\n",
      "2/2 [==============================] - 52s 26s/step - loss: 2.2593 - accuracy: 0.1435 - val_loss: 2.1084 - val_accuracy: 0.4231\n",
      "Epoch 3/3\n",
      "2/2 [==============================] - 51s 26s/step - loss: 2.1924 - accuracy: 0.2348 - val_loss: 2.0070 - val_accuracy: 0.2308\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "<tensorflow.python.keras.callbacks.History at 0x12d95bd68>"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 模型训练：指定训练数据，batchsize,epoch,验证集\n",
    "net.fit(train_images,train_labels,batch_size=128,epochs=3,verbose=1,validation_split=0.1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 模型评估"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "4/4 [==============================] - 11s 3s/step - loss: 2.1049 - accuracy: 0.1484\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "[2.1049132347106934, 0.1484375]"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 指定测试数据\n",
    "net.evaluate(test_images,test_labels,verbose=1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.10"
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": true,
   "sideBar": true,
   "skip_h1_title": false,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {},
   "toc_section_display": true,
   "toc_window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
